﻿using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SHKF.B2C.Model; 
using SHKF.B2C.Network;
using SHKF.B2C.YouZanYun.BLL;
using SHKF.B2C.YouZanYun.Model.Dto;
using SHKF.B2C.YouZanYun.Model.Dto.Secret;
using SHKF.B2C.YouZanYun.Model.Dto.Token;
using SHKF.B2C.YouZanYun.Model.Entity;
using SHKF.B2C.YouZanYun.Model.Inter.UpdateBranch;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
 

namespace SHKF.B2C.YouZanYun.Service
{
    /// <summary>
    /// 复杂架构的实例
    /// </summary>
    public class HttpClientYouZanYunS : HttpClientBase
    {
        private string urlDecryptBatch = "api/youzan.cloud.secret.decrypt.batch/1.0.0";
        private string scrm_token = "/auth/token";

        public string authority_id = "99116298"; //店铺ID

        private long timestamp;
        private string access_token = "";       //token缓存
        private const string client_id = "b1e44d37dd2ff7305f";
        private const string client_secret = "8b1e25b725aadf68d3963b7b3d339c19";

        private readonly ILogger<HttpClientYouZanYunS> logger;
        private readonly TokenBLL tokenBLL;

        public HttpClientYouZanYunS(ILogger<HttpClientYouZanYunS> logger,
            TokenBLL tokenBLL)
        {
            base.BaseAddress = new Uri("https://open.youzanyun.com");
            this.logger = logger;
            this.tokenBLL = tokenBLL;
        }

        /// <summary>
        /// 批量更新库存
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ItemUpdateResult> BranchUpdateStock(StockUpdateRequest data)
        {
            string urlBranchUpdateStock = "";
            ItemUpdateResult stockResult = await this.TPost<ItemUpdateResult>(urlBranchUpdateStock, data);
            return stockResult;
        }


        /// <summary>
        /// 批量解密
        /// </summary>
        /// <param name="sources"></param>
        public async Task<DecryptsDto> DecryptBatch(List<string> sources)
        {
            try
            {
                Dictionary<string, List<string>> data = new Dictionary<string, List<string>>();
                data.Add("sources", sources);

                string json = JsonConvert.SerializeObject(data);
                StringContent stringContent = new StringContent(json);
                stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                urlDecryptBatch += "?access_token=" + this.access_token;
                DecryptsDto dto = new DecryptsDto();
                HttpResponseMessage httpResponseMessage = await base.PostAsync(urlDecryptBatch, stringContent);
                if (httpResponseMessage.IsSuccessStatusCode)
                {
                    string result = await httpResponseMessage.Content.ReadAsStringAsync();
                    dto = await httpResponseMessage.Content.ReadAsAsync<DecryptsDto>();
                }

                return dto;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public long GetTimeStamp()
        {
            DateTime now = DateTime.Now;
            this.timestamp = DateTimeUtil.DateTimeToLongTimeStamp(now);
            return timestamp;
        }

        public async Task<TokenYZYDto> GetToken()
        {
            TokenYZYDto requestToken = null;
            DateTime now = DateTime.Now;
            long timestamp = DateTimeUtil.DateTimeToLongTimeStamp(now.AddHours(1)); //一小时误差

            try
            {
                //数据库存在
                requestToken = this.GetErpToken();

                if (requestToken == null)
                {
                    requestToken = await GetYouZanYunToken(false);
                }
                else
                {
                    if (requestToken.Data.expires <= timestamp) //如果access_token过期
                    {
                        //刷新    
                        if (requestToken.Data.re_expires <= timestamp) //如果刷新时间也过期了,需要重新申请店铺，这是极端事件，需要手动去有赞云
                        {
                            requestToken = null;
                            this.WriteInformation("GetToken", "refresh_expires:如果刷新refresh_expires也过期了,需要重新申请店铺，这是极端事件，需要手动去有赞云的平台操作");
                        }
                        else //如果refresh_token没有过期，重新刷新
                        {
                            requestToken = await GetYouZanYunToken(true);
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                throw ex;
            }

            return requestToken;

        }

        private TokenYZYDto GetErpToken()
        {
            TokenEntity requestToken = this.tokenBLL.Get(authority_id);
            if (requestToken != null)
            {
                TokenDataDto token = new TokenDataDto();
                token.expires = requestToken.expires;
                token.re_expires = requestToken.re_expires;
                token.scope = requestToken.scope;
                token.access_token = requestToken.access_token;
                token.refresh_token = requestToken.refresh_token;
                token.authority_id = requestToken.authority_id;
                TokenYZYDto tokenDto = new TokenYZYDto();
                tokenDto.message = "";
                tokenDto.code = 0;
                tokenDto.Data = token;

                this.access_token = requestToken.access_token;
                return tokenDto;
            }

            return null;
        }

        private void SaveErpToken(TokenYZYDto requestToken)
        {
            TokenDataDto data = requestToken.Data;

            TokenEntity info = new TokenEntity();
            info.access_token = data.access_token;
            info.expires = data.expires;
            info.refresh_token = data.refresh_token;
            info.re_expires = data.re_expires;
            info.scope = "";
            info.authority_id = data.authority_id;

            this.tokenBLL.Save(info);
        }

        private async Task<TokenYZYDto> GetYouZanYunToken(bool refresh = false)
        {
            TokenYZYDto requestToken = null;

            RequestToken info = new RequestToken();
            info.authorize_type = "silent";
            info.client_id = client_id;
            info.client_secret = client_secret;
            info.grant_id = this.authority_id;
            info.refresh = refresh;

            DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(RequestToken));
            MemoryStream msObj = new MemoryStream();

            //将序列化之后的Json格式数据写入流中
            dataContractJsonSerializer.WriteObject(msObj, info);
            msObj.Position = 0;

            //从0这个位置开始读取流中的数据
            StreamReader sr = new StreamReader(msObj, Encoding.UTF8);

            string content = sr.ReadToEnd(); ;
            StringContent stringContent = new StringContent(content);

            MediaTypeHeaderValue mediaTypeHeaderValue = new MediaTypeHeaderValue("application/json");
            stringContent.Headers.ContentType = mediaTypeHeaderValue;

            HttpResponseMessage httpRequestMessage = await base.PostAsync(this.scrm_token, stringContent);

            //读取流
            if (httpRequestMessage.IsSuccessStatusCode)
            {
                string result = await httpRequestMessage.Content.ReadAsStringAsync();
                requestToken = await httpRequestMessage.Content.ReadAsAsync<TokenYZYDto>();
                if (requestToken.code == 200)
                {
                    this.SaveErpToken(requestToken);
                }
                else
                {
                    this.WriteInformation("GetToken", $"code:{requestToken.code} msg:{requestToken.message}");
                    this.access_token = "";
                    return requestToken;
                }
            }
            else
            {
                this.access_token = "";
                return requestToken;
            }

            this.access_token = requestToken.Data.access_token;

            return requestToken;
        }

        private void WriteException(string fun, Exception ex)
        {
            if (this.logger != null)
            {
                this.logger.LogError($"fun:{fun}>> ex:{ex.InnerException.Message}");
            }

        }

        private void WriteInformation(string fun, string msg)
        {
            if (this.logger != null)
            {
                this.logger.LogInformation($"fun:{fun}>> msg:{msg}");
            }
        }

        private async Task<T> TPost<T>(string uriString, object param) where T : new()
        {
            try
            {
                await this.GetToken();
                uriString = uriString + "?access_token=" + this.access_token;

                T dto = new T();
                string json = JsonConvert.SerializeObject(param);
                StringContent stringContent = new StringContent(json);
                stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

                HttpResponseMessage httpResponseMessage = await base.PostAsync(uriString, stringContent);
                if (httpResponseMessage.IsSuccessStatusCode)
                {
                    string STR = await httpResponseMessage.Content.ReadAsStringAsync();

                    dto = await httpResponseMessage.Content.ReadAsAsync<T>();
                }
                else
                {
                    throw new Exception(httpResponseMessage.ToString());
                }

                return dto;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
    }
}
